<?php
$obj = new Lajp();
$num = rand(100000,999999);
/**
 需要本案例使用SM2P7Detached 签名与验签
**/
$dataParams = [
    'head' => [
    		"mertrandate" => "20221027",
        'mertrantime' => '140527',
        'platmerid' => 'CF3000038788', // 平台客户号码
        'trancode' => 'CAS008',
        'tranflow' => 'CF3000038788201810190001_'.$num, // 平台客户号码+订单号+随机数
    ],
    'body' => [
        'oritrancode' => 'CAS006',
        'oritranflow' => 'CF300003878818185128',
    ],
];

// 需要签名的源字符串
$sign_content = json_encode($dataParams);
$messageParams = [
    'data' => $dataParams,
    'sign' => $obj->Sm2SignLajp(true,$sign_content), //签名
    #'sign' => $obj->signLajp(true,$sign_content), //签名
];
$sysDataParams = json_encode(['message' => $messageParams], JSON_UNESCAPED_UNICODE+JSON_FORCE_OBJECT);
$sysDataParams = str_replace('\/', '/', $sysDataParams);
echo "加密原文";
echo $sysDataParams;
$sysDataString = $obj->Sm2EncryptLajp($sysDataParams);
#$sysDataString = $obj->encryptLajp($sysDataParams);

/*
	cert=RSA证书加解密,sm2=SM2证书加解密
	使用RSA证书加解密时:cryptType=cert,signType=cert
	使用SM2证书加解密时:cryptType=sm2,signType=sm2
*/
$sysParams = [
    'formatType' => 'json',
    'cryptType' => 'sm2',
    'signType' => 'sm2',
    'data' => $sysDataString,
];

$result = $obj->request($sysParams);
/*
$result 返回正确json字符串格式如下:
{"message":{"data":{"body":{"feeamount":"0.77","merid":"","payinfo":"weixin://wxpay/bizpayurl?pr=ABC123"},"head":{"clienttime":"20181019142133","platmerid":"CF2000000001","respcode":"W000000000","respmsg":"交易处理中","trancode":"QR1008","tranflow":"CF2000000001201810190001_21680"}},"sign":"Qngxx/ko14D0cAEaVgpyF/K1yDQb4IrzmP0AMWoE4LfUNix51d1TXRGwxmyAb/nHGzvFxOsDmcPcRH5Oa/tsZtu7YQVaa853TNpcxEaeA6aCWBLLwsztoBBNpeers30CqHJ0UTyeMnr5I/SI5yZ69X8sJBvCjAESHcZ137HXfSL7yFV0gd9Wqg3JRB9hM33IiUY/G8hR4LU8X7UsR4G98AIkoedkkI9pjAAA1VLBFxa0WEjesl37iQFx8HRPGkE8MTEuXeujd5KmCTQEqYQtVKXD8z9RD+y/gxazJ5Kgvt6N6D397OPmZAkaoVGqQ2ZzLnW6NqZ1JVbZevSisqYNYw=="}}
 */
var_dump($result);
$res = $obj->checkResult($result);
var_dump($res);
/*
$res 返回正确数据格式如下（该数据格式为自定义）:
array
(
    'status' => 1,
    'message' => '',
    'data' => array
    (
        'payinfo' => 'weixin://wxpay/bizpayurl?pr=ABC123',
        'trans_order_no' => '201810190001',
        'tranflow' => 'CF2000000001201810190001_21680',
    )
)
 */

class Lajp
{
    //网关
    public static $gatewayUrl = "http://test.umbpay.com.cn:12080/cashier/transV2/service.do";
    //以下为RSA证书信息
    public static $RsaPrivateKeyFilePath;
    public static $RsaPrivateKeyFilePassword;
    public static $RsaPublicKeyFilePath;
    //以下为SM2证书信息
    //SM2签名私钥文件路径
    public static $SM2SignPrivateKeyFilePath;
    //SM2签名私钥密码
    public static $SM2SignPrivateKeyFilePassword;
    //SM2加密私钥文件路径
    public static $SM2EncPrivateKeyFilePath;
    //SM2加密私钥密码
    public static $SM2EncPrivateKeyFilePassword;
    //SM2验签公钥文件路径(平台提供)
    public static $SM2SignPublicKeyFilePath;
    //SM2加密公钥文件路径(平台提供)
    public static $SM2EncPublicKeyFilePath;


    function __construct()
    {
    		//以下为RSA证书信息
        self::$RsaPrivateKeyFilePath = '../cer/merchant.pfx';
        self::$RsaPrivateKeyFilePassword = 'umbpay';
        self::$RsaPublicKeyFilePath = '../cer/platform.cer';
        //以下为SM2证书信息
        self::$SM2SignPrivateKeyFilePath = '../cer/mechant_sign_sm2.sm2';
        self::$SM2SignPrivateKeyFilePassword = 'UMBPAY2022';
        self::$SM2EncPrivateKeyFilePath = '../cer/mechant_enc_sm2.sm2';
        self::$SM2EncPrivateKeyFilePassword = 'UMBPAY2022';
        self::$SM2SignPublicKeyFilePath = '../cer/platfrom_sign_sm2.cer';
        self::$SM2EncPublicKeyFilePath = '../cer/platfrom_enc_sm2.cer';
    }

 /**
     * 使用LAJP工具包获取SM2数据签名
     * @return 索引
     */
    public function signLajp($get_index,$data)
    {
    		require_once("php_java.php");
    		$sign = '';
        $password = self::$RsaPrivateKeyFilePassword;
        $RsaSignPrivateKeyFilePath = self::$RsaPrivateKeyFilePath;
        if($get_index)
        {
            echo "签名内容[";
            echo $data;
            echo "]\r\n";
            $base64SourceString = base64_encode($data);
            $signAlg = 'SHA256withRSAEncryption';
		        $signRet = lajp_call("cfca.sadk2.api.SignatureKitSm2::P1SignMessageRsa",  $signAlg,$base64SourceString, $RsaSignPrivateKeyFilePath, $password);
		        $signArr = json_decode($signRet);
		        $sign = $signArr->Base64SignatureString;
		        echo "签名值[";
		        echo $sign;
		        echo "]\r\n";
		        return $sign;
        }

    }


    /**
     * 使用LAJP工具包验证SM2签名
     * @param  string $body body数据
     * @param  string $sign 签名字符串
     * @return 签名
     */
    public function verifySignLajp($body, $sign)
    {
        require_once("php_java.php");
        try
        {
            $signAlg = 'SHA256withRSAEncryption';
            $sign_content = $this->getSignContent($body);
            $base64SourceString = base64_encode($sign_content);
            $cer = self::$RsaPublicKeyFilePath;
            $base64SignatureString = base64_encode($sign);
            $ret = lajp_call("cfca.sadk2.api.SignatureKitSm2::P1VerifyMessageRsa", $signAlg, $base64SourceString, $cer, $base64SignatureString);
            $arr = json_decode($ret);
            $verCode = $arr->Code;
            $verResult = $arr->Result;
            echo "验签结果[";
            echo $verCode;
            echo  "][";
            echo $verResult;
            echo "]";

            if(isset($arr->Result) && $arr->Result && $arr->Code == '90000000')
            {
                return true;
            }
            else
            {
                Yii::error('UmbPay Verify Sign Failed: ' . $arr->Code);
                return false;
            }
        }
        catch(\Exception $e)
        {
            Yii::error($e);
        }
    }

    /**
     * 使用LAJP工具包SM2算法加密
     * @param  string $data 源字符串
     * @return 密文
     */
    public function encryptLajp($data)
    {
        $Sm2Encrypt = '';
        require_once("php_java.php");
        try
        {
            $RsasignAlg = 'DESede/CBC/PKCS7Padding';
            $Rsabase64CertData = file_get_contents(self::$RsaPublicKeyFilePath);
            $Rsabase64CertData = str_replace(['-----BEGIN CERTIFICATE-----','-----END CERTIFICATE-----'], ['',''], $Rsabase64CertData);
            $RsaBase64SourceData = base64_encode($data);
            	echo "base64[";
						echo $RsaBase64SourceData;
						echo "]base64";
            $ret = lajp_call("cfca.sadk2.api.EnvelopeKitSm2::envelopeMessage", $RsaBase64SourceData, $RsasignAlg, $Rsabase64CertData);
            $arr = json_decode($ret);
            $RsaEncrypt = $arr->Base64EnvelopeMessage;
            echo "RSA加密结果[";
            echo $RsaEncrypt;
         		echo "]";
         		$res = base64_decode($RsaEncrypt);
        }
        catch(\Exception $e)
        {
            Yii::error($e);
        }
        return $res;
    }


/**
     * 使用LAJP工具包SM2算法解密
     * @param  string $data 源密文字符串
     * @return 明文
     */
    public function decryptLajp($data)
    {
        $decrypt = '';
        require_once("php_java.php");
        try
        {
            $password = self::$RsaPrivateKeyFilePassword;
		        $priKey = self::$RsaPrivateKeyFilePath;
            $base64EnvelopeMessage = base64_decode($data);
            $ret = lajp_call("cfca.sadk2.api.EnvelopeKitSm2::openEvelopedMessageRsa", $base64EnvelopeMessage, $priKey, $password);
            $arr = json_decode($ret, true);
            $decrypt = isset($arr['Base64SourceString']) ? base64_decode($arr['Base64SourceString']) : NULL;
            echo "服务器返回解密后:";
            echo $decrypt;
            echo "\r\n";
        }
        catch(\Exception $e)
        {
            Yii::error($e);
        }
        return $decrypt;
    }


     /**
     * 使用LAJP工具包获取SM2数据签名
     * @return 索引
     */
    public function Sm2SignLajp($get_index,$data)
    {
    		require_once("php_java.php");
    		$sign = '';
        $password = self::$SM2SignPrivateKeyFilePassword;
        $SM2SignPrivateKeyFilePath = self::$SM2SignPrivateKeyFilePath;
        if($get_index)
        {
            echo "签名内容[";
            echo $data;
            echo "]\r\n";
            $base64SourceString = base64_encode(str_replace(" ","+",$data));#str_replace(" ","+",$_GET['str'])
            $signAlg = 'sm3WithSM2Encryption';
		        $signRet = lajp_call("cfca.sadk2.api.SignatureKitSm2::P7SignMessageSm2Detached",  $signAlg,$base64SourceString, $SM2SignPrivateKeyFilePath, $password);
		        $signArr = json_decode($signRet);
		        $sign = $signArr->Base64SignatureString;
		        echo "签名值[";
		        echo $sign;
		        echo "]\r\n";
		        return $sign;
        }

    }


    /**
     * 使用LAJP工具包验证SM2签名
     * @param  string $body body数据
     * @param  string $sign 签名字符串
     * @return 签名
     */
    public function Sm2VerifySignLajp($body, $sign)
    {
        require_once("php_java.php");
        try
        {
            $signAlg = 'SM3withSM2';
            $sign_content = json_encode($body,JSON_UNESCAPED_UNICODE+JSON_FORCE_OBJECT);
            echo "验签字符串[";
            echo $sign_content;
            echo  "]";
            $base64SourceString = base64_encode($sign_content);
            $base64SignatureString = base64_encode($sign);
            $ret = lajp_call("cfca.sadk2.api.SignatureKitSm2::P7VerifyMessageSm2Detached", $signAlg, $base64SourceString, $base64SignatureString);
            $arr = json_decode($ret);
            $verCode = $arr->Code;
            $verResult = $arr->Result;
            echo "验签结果[";
            echo $verCode;
            echo  "][";
            echo $verResult;
            echo "]";

            if(isset($arr->Result) && $arr->Result && $arr->Code == '90000000')
            {
                return true;
            }
            else
            {
                Yii::error('UmbPay Verify Sign Failed: ' . $arr->Code);
                return false;
            }
        }
        catch(\Exception $e)
        {
            Yii::error($e);
        }
    }

    /**
     * 使用LAJP工具包SM2算法加密
     * @param  string $data 源字符串
     * @return 密文
     */
    public function Sm2EncryptLajp($data)
    {
        $Sm2Encrypt = '';
        require_once("php_java.php");
        try
        {
            $sm2signAlg = 'SM4/ECB/PKCS7Padding';
            $sm2base64CertData = file_get_contents(self::$SM2EncPublicKeyFilePath);
            $sm2base64CertData = str_replace(['-----BEGIN CERTIFICATE-----','-----END CERTIFICATE-----'], ['',''], $sm2base64CertData);
            $sm2Base64SourceData = base64_encode($data);
            	echo "base64[";
						echo $sm2Base64SourceData;
						echo "]";
            $ret = lajp_call("cfca.sadk2.api.EnvelopeKitSm2::envelopeMessageSm2", $sm2Base64SourceData, $sm2signAlg, $sm2base64CertData);
            $arr = json_decode($ret);
            $Sm2Encrypt = $arr->Base64EnvelopeMessage;
            echo "SM2加密结果[";
            echo $Sm2Encrypt;
         		echo "]";
        }
        catch(\Exception $e)
        {
            Yii::error($e);
        }
        return $Sm2Encrypt;
    }


/**
     * 使用LAJP工具包SM2算法解密
     * @param  string $data 源密文字符串
     * @return 明文
     */
    public function Sm2DecryptLajp($data)
    {
        $decrypt = '';
        require_once("php_java.php");
        try
        {
            $password = self::$SM2EncPrivateKeyFilePassword;
		        $priKey = self::$SM2EncPrivateKeyFilePath;
            //$base64EnvelopeMessage = base64_decode($data);
            $ret = lajp_call("cfca.sadk2.api.EnvelopeKitSm2::openEvelopedMessageSm2", $data, $priKey, $password);
            $arr = json_decode($ret, true);
            $decrypt = isset($arr['Base64SourceString']) ? base64_decode($arr['Base64SourceString']) : NULL;
            echo "服务器返回SM2解密后:";
            echo $decrypt;
            echo "\r\n";
        }
        catch(\Exception $e)
        {
            Yii::error($e);
        }
        return $decrypt;
    }

    /**
     * 拼接参数
     * @param  array $params 源数组参数
     * @return 拼接后的字符串
     */
    public function getSignContent($params)
    {
        $stringToBeSigned = '';
        foreach($params as $key => $val)
        {
            $stringToBeSigned .= $key . '=' . $val . "&amp;";
        }
        $stringToBeSigned = str_replace("\r\n", "", $stringToBeSigned);
        $stringToBeSigned = htmlspecialchars_decode($stringToBeSigned);
        return $stringToBeSigned;
    }

    /**
     * CURL推送数据
     */
    public function request($args)
    {
        $ch = curl_init () ;
        curl_setopt($ch, CURLOPT_URL, self::$gatewayUrl);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($ch, CURLOPT_HEADER, 0);
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, $args);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_AUTOREFERER, 0);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
        $result = curl_exec($ch);
        echo "发送请求";
          echo "响应:";
        echo $result;
        echo "\r\n";
        curl_close($ch);

        return $this->Sm2DecryptLajp($result);
    }

    /**
     * 检查服务调用结果是否正确，如果服务调用失败，则抛出失败异常
     * @param result 服务调用的返回结果对象
     * @throws Exception
     */
    public function checkResult($result)
    {
        $res = ['status' => 0, 'message' => '', 'data' => []];
        $arr = json_decode($result, true);
        try
        {
            $data = $arr['message']['data'];
            $sign = $arr['message']['sign'];
             echo "签名域[";
            echo $sign;
            echo "\r\n";
            if($sign != null){
                $seccess = $this->Sm2VerifySignLajp($data, $sign);
                if(!$seccess)
                    throw new Exception("返回值签名验证失败");
            }
            // 如果是查询支付
            if(isset($data['body']['orirespcode']))
            {
                $res['status'] = 1;
                $res['data'] = $data['body'];
                // 支付成功
                if($data['body']['orirespcode'] == 'C000000000')
                {
                    $res['data']['pay_result'] = 'succeed';
                }
                // 支付进行中
                else if($data['body']['orirespcode'] == 'W000000000')
                {
                    $res['data']['pay_result'] = 'padding';
                }
                // 其他状态视为支付失败
                else
                {
                    $res['data']['pay_result'] = 'failed';
                }
                $res['data']['clienttime'] = $data['head']['clienttime'];
            }
            // 获取订单号
            else if($data['head']['respcode'] == 'W000000000' || $data['head']['respcode'] == 'C000000000')
            {
                $out_order_nos = explode('_', $data['head']['tranflow']);
                $trans_order_no = substr($out_order_nos[0], 12);
                $res['data']['payinfo'] = $data['body']['payinfo'];
                $res['data']['trans_order_no'] = $trans_order_no;
                $res['data']['tranflow'] = $data['head']['tranflow'];
                $res['status'] = 1;
            }
            else
            {
                $res['message'] = $data['head']['respmsg'];
                $res['data']['payinfo'] = '';
                $res['data']['trans_order_no'] = '';
                $res['data']['tranflow'] = '';
            }
            return $res;
        }
        catch(\Exception $e)
        {
            $res['message'] = $e->getMessage();
        }
        return $res;
    }
    
    
    
		
}